package com.eagle.scali.contentcenter.service.content;

import com.alibaba.fastjson.JSON;
import com.eagle.scali.contentcenter.dao.content.MidUserShareMapper;
import com.eagle.scali.contentcenter.dao.content.ShareMapper;
import com.eagle.scali.contentcenter.dao.messaging.RocketmqTransactionLogMapper;
import com.eagle.scali.contentcenter.domain.dto.content.ShareAuditDTO;
import com.eagle.scali.contentcenter.domain.dto.content.ShareDTO;
import com.eagle.scali.contentcenter.domain.dto.messaging.UserAddBonusMsgDTO;
import com.eagle.scali.contentcenter.domain.dto.user.UserAddBonseDTO;
import com.eagle.scali.contentcenter.domain.dto.user.UserDTO;
import com.eagle.scali.contentcenter.domain.entity.content.MidUserShare;
import com.eagle.scali.contentcenter.domain.entity.content.Share;
import com.eagle.scali.contentcenter.domain.entity.messaging.RocketmqTransactionLog;
import com.eagle.scali.contentcenter.domain.enums.AuditStatusEnum;
import com.eagle.scali.contentcenter.feignclient.UserCenterFeignClient;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.support.RocketMQHeaders;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.http.ResponseEntity;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ShareService {
	@Autowired(required = false)
    private ShareMapper shareMapper;

	@Autowired(required = false)
	private Source source;

	@Autowired(required = false)
	private RocketmqTransactionLogMapper rocketmqTransactionLogMapper;

	@Autowired(required = false)
	private MidUserShareMapper midUserShareMapper;

//    这里不能是resource注解
    @Autowired
	private UserCenterFeignClient userCenterFeignClient;

    public ShareDTO findById(Integer id) {
        // 获取分享详情
        Share share = this.shareMapper.selectByPrimaryKey(id);
        // 发布人id
        Integer userId = share.getUserId();

		UserDTO userDTO = this.userCenterFeignClient.findById(userId);
		ShareDTO shareDTO = new ShareDTO();
        // 消息的装配
        BeanUtils.copyProperties(share, shareDTO);
        shareDTO.setWxNickname(userDTO.getWxNickname());
        return shareDTO;
    }

	public List<ShareDTO> findByUserId(@RequestBody List<String> userIds) {
//		List<String> userIds = Lists.transform(userDtoList, input -> input.getId().toString());
		List<Share> shareList = this.shareMapper.selectByUserIds(userIds);
		List<ShareDTO> shareDTOList = shareList.stream().map(s -> {
			ShareDTO shareDTO = new ShareDTO();
			BeanUtils.copyProperties(s, shareDTO);
			return shareDTO;
		}).collect(Collectors.toList());

		return shareDTOList;
	}

	/**
	 * 这个方法不需要事务了，因为已经由rocketMQ实现了
	 *
	 * @param id
	 * @param auditDTO
	 * @return Share
	 */
	public Share auditById(Integer id, ShareAuditDTO auditDTO) {
		Share share = this.shareMapper.selectByPrimaryKey(id);
		if (share == null) {
			throw new IllegalArgumentException("参数非法！该分享不存在！");
		}
		if (!Objects.equals("NOT_YET", share.getAuditStatus())) {
			throw new IllegalArgumentException("参数非法！该分享已审核通过或审核不通过！");
		}

		if (AuditStatusEnum.PASS.equals(auditDTO.getAuditStatusEnum())) {
//			/**
//			 * 发送半消息,包含
//			 * share_id 要分享的文章的主键id
//			 * transactionId 事务id给rocketmq用
//			 * UserAddBonusMsgDTO 主体信息
//			 */
//			String transactionId = UUID.randomUUID().toString();
//
//			this.source.output().send(MessageBuilder.withPayload(
//					UserAddBonusMsgDTO.builder()
//							.userId(share.getUserId())
//							.bonus(50).build()
//			).setHeader(RocketMQHeaders.TRANSACTION_ID, transactionId)
//					.setHeader("share_id", id)
//					.setHeader("dto", JSON.toJSONString(auditDTO))
//					.build());


			//为了不启动mq,这里用feign代替
			this.userCenterFeignClient.addBonus(
					UserAddBonusMsgDTO.builder()
							.userId(share.getUserId())
							.bonus(share.getPrice()).build()
			);

		}
		auditByIdInDB(id,auditDTO);
		share.setReason(auditDTO.getReason());
		share.setAuditStatus(auditDTO.getAuditStatusEnum().name());
		return share;
	}

	/**
	 * @param userid
	 * @param shareDTO
	 * @return Share
	 */
	public Share contributeShare(Integer userid, ShareDTO shareDTO) {
		Share share = Share.builder().userId(userid)
				.title(shareDTO.getTitle())
				.createTime(new Date()).updateTime(new Date())
				.isOriginal(shareDTO.getIsOriginal())
				.author(shareDTO.getAuthor())
				.cover(shareDTO.getCover())
				.summary(shareDTO.getSummary())
				.price(shareDTO.getPrice())
				.downloadUrl(shareDTO.getDownloadUrl())
				.buyCount(shareDTO.getBuyCount())
				.showFlag(shareDTO.getShowFlag())
				.auditStatus(AuditStatusEnum.NOT_YET.name()).build();
		this.shareMapper.insertSelective(share);
		return share;
	}

	@Transactional(rollbackFor = Exception.class)
	public void auditByIdInDB(Integer id, ShareAuditDTO auditDTO) {
		Share share = Share.builder()
				.id(id)
				.auditStatus(auditDTO.getAuditStatusEnum().toString())
				.reason(auditDTO.getReason())
				.build();
		this.shareMapper.updateByPrimaryKeySelective(share);
	}

	public PageInfo<Share> q(String title, Integer pageNo, Integer pageSize, Integer userId) {
		PageHelper.startPage(pageNo, pageSize);
		List<Share> shares = this.shareMapper.selectByParam(title);
		List<Share> sharesDeal;
		// 1. 如果用户未登录，那么downloadUrl全部设为null
		/**
		 * peek 接收一个没有返回值的λ表达式，可以做一些输出，外部处理等
		 * map  接收一个有返回值的λ表达式，之后Stream的泛型类型将转换为map参数λ表达式返回的类型
		 */
		if (userId == null) {
			sharesDeal = shares.stream()
					.peek(share -> {
						share.setDownloadUrl(null);
					})
					.collect(Collectors.toList());
		}
		// 2. 如果用户登录了，那么查询一下mid_user_share，如果没有数据，那么这条share的downloadUrl也设为null
		else {
			sharesDeal = shares.stream()
					.peek(share -> {
						MidUserShare midUserShare = this.midUserShareMapper.selectOne(
								MidUserShare.builder()
										.userId(userId)
										.shareId(share.getId())
										.build()
						);
						if (midUserShare == null) {
							share.setDownloadUrl(null);
						}
					})
					.collect(Collectors.toList());
		}
		return new PageInfo<>(sharesDeal);
	}

	public Share exchangeById(Integer id, HttpServletRequest request) {
		Object userId = request.getAttribute("id");
		Integer integerUserId = (Integer) userId;

		// 1. 根据id查询share，校验是否存在
		Share share = this.shareMapper.selectByPrimaryKey(id);
		if (share == null) {
			throw new IllegalArgumentException("该分享不存在！");
		}
		Integer price = share.getPrice();

		// 2. 如果当前用户已经兑换过该分享，则直接返回
		MidUserShare midUserShare = this.midUserShareMapper.selectOne(
				MidUserShare.builder()
						.shareId(id)
						.userId(integerUserId)
						.build()
		);
		if (midUserShare != null) {
			return share;
		}

		// 3. 根据当前登录的用户id，查询积分是否够
		UserDTO userDTO = this.userCenterFeignClient.findById(integerUserId);
		if (price > userDTO.getBonus()) {
			throw new IllegalArgumentException("用户积分不够用！");
		}

		//4 更新下载数
		share.setBuyCount(share.getBuyCount()+1);
		this.shareMapper.updateByPrimaryKeySelective(share);

		// 5. 扣减积分 & 往mid_user_share里插入一条数据
		this.userCenterFeignClient.reduceBonus(
				UserAddBonseDTO.builder()
						.userId(integerUserId)
						.bonus(0 - price)
						.build()
		);

		//6. 添加兑换记录
		this.midUserShareMapper.insert(
				MidUserShare.builder()
						.userId(integerUserId)
						.shareId(id)
						.build()
		);
		return share;
	}

	public static void main(String[] args) {
        RestTemplate restTemplate = new RestTemplate();
        // 用HTTP GET方法去请求，并且返回一个对象
        ResponseEntity<String> forEntity = restTemplate.getForEntity(
            "http://localhost:8080/users/{id}",
            String.class, 2
        );

        System.out.println(forEntity.getBody());
        // 200 OK
        // 500
        // 502 bad gateway...
        System.out.println(forEntity.getStatusCode());
    }

	@Transactional(rollbackFor = Exception.class)
	public void auditByIdWithRocketMqLog(Integer id, ShareAuditDTO auditDTO, String transactionId) {
    	//更新文章状态和和分享原因
		this.auditByIdInDB(id, auditDTO);
		//当服务端回查生产者时候，生产者根据这条事务ID找到对应的记录
		this.rocketmqTransactionLogMapper.insertSelective(
				RocketmqTransactionLog.builder()
						.transactionId(transactionId)
						.log("审核分享...")
						.build()
		);
	}

	public List<Share>  getExchangeBook(Integer userId) {
		MidUserShare midUserShare = new MidUserShare();
		midUserShare.setUserId(userId);
		List<MidUserShare> exchangeBooks = this.midUserShareMapper.select(midUserShare);
		List<Share> shareList = new ArrayList<>();
		exchangeBooks.stream().peek(s ->{
			Share share = Share.builder().id(s.getShareId()).build();
			shareList.add(this.shareMapper.selectOne(share));
		}).collect(Collectors.toList());
		return shareList;
	}
}

